using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NBear.Common;

namespace NBear.Test.UnitTests
{
    public interface IParent : IEntity
    {
        [PrimaryKey]
        int ID { get; }
        [ColumnName("ParentID")]
        int ID2 { get; set; }
    }

    public interface IMiddle : IParent
    {
        int Middle { get; set; }
        int Middle2 { get; }
    }

    [Table("TestChild")]
    public interface IChild : IMiddle
    {
        string Name { get; set; }
        string Name2 { get; set; }
    }

    public class ParentCustomImpl : Entity<IParent>, IParent
    {
        public ParentCustomImpl() : base() { }

        #region IParent Members

        public int ID
        {
            get { return (int)keyValues[0]; }
        }

        public int ID2
        {
            get
            {
                return 8000 + (int)keyValues[1];
            }
            set
            {
                CheckOriginalKeyValues();
                keyValues[1] = value;
            }
        }

        #endregion

        #region IEntity Members

        public KeyValueCollection GetKeyValues() { return keyValues; }

        public new KeyValueCollection GetOriginalKeyValues() { return base.GetOriginalKeyValues(); }

        public new void UpdateOriginalKeyValues() { base.UpdateOriginalKeyValues(); }

        #endregion
    }

    public interface ISimple : IEntity
    {
        [PrimaryKey]
        int ID { get; set; }
        string Name { get; set; }
    }

    public interface ICombined : IEntity
    {
        [PrimaryKey]
        int ID1 { get; set; }
        [PrimaryKey]
        int ID2 { get; set; }
        int Weight { get; set; }
    }

    /// <summary>
    /// Summary description for TestEntityFactory
    /// </summary>
    [TestClass]
    public class TestEntityFactory
    {
        public TestEntityFactory()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        [TestMethod]
        public void TestInhertedEntity()
        {
            Assert.AreEqual(Entity<IChild>.GetColumnNames().Length, 6);

            Assert.AreEqual(Entity<IChild>.GetPrimaryKeyColumnNames().Length, 1);

            Assert.AreEqual(Entity<IChild>.GetPropertyMappedColumn("ID2"), "ParentID");

            Assert.AreEqual(Entity<IChild>.GetTableName(), "TestChild");
        }

        [TestMethod]
        public void TestEntityCreate()
        {
            IChild obj = EntityFactory<IChild>.CreateObject();

            obj.ID2 = 2;
            obj.Middle = 3;
            obj.Name = "name1";
            obj.Name2 = "name2";

            Assert.AreEqual(obj.GetKeyValues().GetKeys().Length, obj.GetOriginalKeyValues().GetKeys().Length);

            BaseEntityFactory.RegisterCustomEntity(typeof(IParent), typeof(ParentCustomImpl));
            IParent obj2 = EntityFactory<IParent>.CreateObject();
            obj2.ID2 = 11;
            Assert.AreEqual(obj2.ID2, 8011);

            BaseEntityFactory.UnregisterCustomEntity(typeof(IParent));
            obj2 = EntityFactory<IParent>.CreateObject();
            obj2.ID2 = 11;
            Assert.AreEqual(obj2.ID2, 11);
        }

        [TestMethod]
        public void TestDifferentEntityColumns()
        {
            Assert.AreEqual(Entity<ISimple>.GetColumnNames().Length, 2);

            Assert.AreEqual(Entity<ICombined>.GetPrimaryKeyColumnNames().Length, 2);

            Assert.AreEqual(Entity<IParent>.GetReadOnlyColumnNames().Length, 1);

            Assert.AreEqual(Entity<IMiddle>.GetReadOnlyColumnNames().Length, 2);

            Assert.AreEqual(Entity<IChild>.GetReadOnlyColumnNames().Length, 2);

            Assert.AreEqual(Entity<IParent>.GetReadOnlyColumnNames()[0], "ID");

            ISimple obj1 = EntityFactory<ISimple>.CreateObject();

            ICombined obj2 = EntityFactory<ICombined>.CreateObject();
        }
    }
}
